diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.c src/ice/ice_candidate.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_candidate.c	2012-10-06 08:30:22.000000000 -0700
@@ -54,36 +54,38 @@
 
 #include "stun_client_ctx.h"
 #include "stun_server_ctx.h"
 #include "turn_client_ctx.h"
 #include "ice_ctx.h"
 #include "ice_candidate.h"
 #include "ice_reg.h"
 #include "ice_util.h"
 #include "nr_socket_turn.h"
 
+static int next_automatic_preference = 224;
+
 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg);
-static void nr_ice_srvrflx_stun_finished_cb(int sock, int how, void *cb_arg);
+static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
 #ifdef USE_TURN
 static int nr_ice_start_relay_turn(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg);
-static void nr_ice_turn_allocated_cb(int sock, int how, void *cb_arg);
+static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
 #endif /* USE_TURN */
 
 char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
 
 int nr_ice_candidate_create(nr_ice_ctx *ctx,char *label,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
   {
     nr_ice_candidate *cand=0;
     nr_ice_candidate *tmp=0;
     int r,_status;
- 
+
     if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
       ABORT(R_NO_MEMORY);
     if(!(cand->label=r_strdup(label)))
       ABORT(R_NO_MEMORY);
     cand->state=NR_ICE_CAND_STATE_CREATED;
     cand->ctx=ctx;
     cand->isock=isock;
     cand->osock=osock;
     cand->type=ctype;
     cand->stun_server=stun_server;
@@ -189,21 +191,21 @@
     if(cand->delay_timer)
       NR_async_timer_cancel(cand->delay_timer);
 
     RFREE(cand->foundation);
     RFREE(cand->label);
     RFREE(cand);
     
     return(0);
   }
 
-void nr_ice_candidate_destroy_cb(int s, int h, void *cb_arg)
+void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg)
   {
     nr_ice_candidate *cand=cb_arg;
     nr_ice_candidate_destroy(&cand);
   }
 
 /* This algorithm is not super-fast, but I don't think we need a hash
    table just yet and it produces a small foundation string */
 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand)
   {
     nr_ice_foundation *foundation;
@@ -276,22 +278,38 @@
         break;
       default:
         ABORT(R_INTERNAL);
     }
 
     if(type_preference > 126)
       r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
 
       
     if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
-      &interface_preference))
-      ABORT(r);
+      &interface_preference)) {
+      if (r==R_NOT_FOUND) {
+        if (next_automatic_preference == 1) {
+          r_log(LOG_ICE,LOG_DEBUG,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
+          ABORT(R_NOT_FOUND);
+        }
+        r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
+          next_automatic_preference);
+        if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
+          ABORT(r);
+        }
+        interface_preference=next_automatic_preference;
+        next_automatic_preference--;
+      }
+      else {
+        ABORT(r);
+      }
+    }
 
     cand->priority=
       (type_preference << 24) |
       (interface_preference << 16) |
       (stun_priority << 8) |
       (256 - cand->component_id);
 
     /* S 4.1.2 */    
     assert(cand->priority>=1&&cand->priority<=2147483647);
 
@@ -306,21 +324,22 @@
 
     cand->done_cb=ready_cb;
     cand->cb_arg=cb_arg;
 
     switch(cand->type){
       case HOST:
         if(r=nr_socket_getaddr(cand->isock->sock,&cand->addr))
           ABORT(r);
         cand->osock=cand->isock->sock;
         cand->state=NR_ICE_CAND_STATE_INITIALIZED;
-        ready_cb(0,0,cb_arg);
+        // Post this so that it doesn't happen in-line
+        NR_ASYNC_SCHEDULE(ready_cb,cb_arg);
         break;
 #ifdef USE_TURN
       case RELAYED:
         if(r=nr_ice_start_relay_turn(cand,ready_cb,cb_arg))
           ABORT(r);
         ABORT(R_WOULDBLOCK);
         break;
 #endif /* USE_TURN */
       case SERVER_REFLEXIVE:
         /* Need to start stun */
@@ -333,21 +352,21 @@
         ABORT(R_INTERNAL);
     }
 
     _status=0;
   abort:
     if(_status && _status!=R_WOULDBLOCK)
       cand->state=NR_ICE_CAND_STATE_FAILED;
     return(_status);
   }
 
-static void nr_ice_srvrflx_start_stun_timer_cb(int s, int how, void *cb_arg)
+static void nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_candidate *cand=cb_arg;
     int r,_status;
 
     cand->delay_timer=0;
 
 /* TODO: if the response is a BINDING-ERROR-RESPONSE, then restart
  * TODO: using NR_STUN_CLIENT_MODE_BINDING_REQUEST because the
  * TODO: server may not have understood the 0.96-style request */
     if(r=nr_stun_client_start(cand->u.srvrflx.stun, NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96, nr_ice_srvrflx_stun_finished_cb, cand))
@@ -387,21 +406,21 @@
 
     _status=0;
   abort:
     if(_status){
       cand->state=NR_ICE_CAND_STATE_FAILED;
     }
     return(_status);
   }
 
 #ifdef USE_TURN
-static void nr_ice_start_relay_turn_timer_cb(int s, int how, void *cb_arg)
+static void nr_ice_start_relay_turn_timer_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_candidate *cand=cb_arg;
     int r,_status;
     int i;
 
     cand->delay_timer=0;
 
     if(r=nr_turn_client_allocate(cand->u.relayed.turn, cand->u.relayed.server->username, cand->u.relayed.server->password, cand->u.relayed.server->bandwidth_kbps, cand->u.relayed.server->lifetime_secs, nr_ice_turn_allocated_cb, cand))
       ABORT(r);
 
@@ -443,21 +462,21 @@
 
     _status=0;
   abort:
     if(_status){
       cand->state=NR_ICE_CAND_STATE_FAILED;
     }
     return(_status);
   }
 #endif /* USE_TURN */
 
-static void nr_ice_srvrflx_stun_finished_cb(int sock, int how, void *cb_arg)
+static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg)
   {
     int _status;
     nr_ice_candidate *cand=cb_arg;
 
     /* Deregister to suppress duplicates */
     if(cand->u.srvrflx.stun_handle){ /* This test because we might have failed before CB registered */
       nr_ice_socket_deregister(cand->isock,cand->u.srvrflx.stun_handle);
       cand->u.srvrflx.stun_handle=0;
     }
 
@@ -481,40 +500,40 @@
     }
     _status = 0;
   abort:
     if(_status){
       cand->state=NR_ICE_CAND_STATE_FAILED;
       cand->done_cb(0,0,cand->cb_arg);
     }
   }
 
 #ifdef USE_TURN
-static void nr_ice_turn_allocated_cb(int s, int how, void *cb_arg)
+static void nr_ice_turn_allocated_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     int r,_status;
     nr_ice_candidate *cand=cb_arg;
     nr_turn_client_ctx *turn=cand->u.relayed.turn;
     int i;
     char *label;
 
     /* Deregister to suppress duplicates */
     if(cand->u.relayed.turn_handle){ /* This test because we might have failed before CB registered */
       nr_ice_socket_deregister(cand->isock,cand->u.relayed.turn_handle);
       cand->u.relayed.turn_handle=0;
     }
 
     switch(turn->state){
     /* OK, we should have a mapped address */
     case NR_TURN_CLIENT_STATE_ALLOCATED:
         /* switch candidate from TURN mode to STUN mode */
 
-        if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",turn->relay_addr.as_string,")",0))
+        if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",turn->relay_addr.as_string,")",NULL))
           ABORT(r);
 
         r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Switching from TURN (%s) to RELAY (%s)",cand->u.relayed.turn->label,cand->label,label);
 
         /* Copy out mapped address and relay address */
         nr_transport_addr_copy(&turn->relay_addr, &cand->u.relayed.turn->stun_ctx[NR_TURN_CLIENT_PHASE_ALLOCATE_REQUEST2]->results.allocate_response2.relay_addr);
         nr_transport_addr_copy(&cand->addr, &turn->relay_addr);
 
         r_log(LOG_ICE,LOG_DEBUG,"ICE-CANDIDATE(%s): base=%s, candidate=%s", cand->label, cand->base.as_string, cand->addr.as_string);
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.h src/ice/ice_candidate.h
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate.h	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_candidate.h	2012-10-06 08:30:22.000000000 -0700
@@ -41,21 +41,22 @@
 
 typedef enum {HOST=1, SERVER_REFLEXIVE, PEER_REFLEXIVE, RELAYED} nr_ice_candidate_type;
 
 struct nr_ice_candidate_ {
   char *label;
   int state;
 #define NR_ICE_CAND_STATE_CREATED          1
 #define NR_ICE_CAND_STATE_INITIALIZING     2
 #define NR_ICE_CAND_STATE_INITIALIZED      3
 #define NR_ICE_CAND_STATE_FAILED           4
-#define NR_ICE_CAND_PEER_CANDIDATE         10
+#define NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED 9
+#define NR_ICE_CAND_PEER_CANDIDATE_PAIRED   10
   struct nr_ice_ctx_ *ctx;
   nr_ice_socket *isock;               /* The socket to read from
                                          (it contains all other candidates
                                          on this socket) */
   nr_socket *osock;                   /* The socket to write to */
   nr_ice_media_stream *stream;        /* The media stream this is associated with */
   nr_ice_component *component;        /* The component this is associated with */
   nr_ice_candidate_type type;         /* The type of the candidate (S 4.1.1) */
   UCHAR component_id;                 /* The component id (S 4.1.2.1) */
   nr_transport_addr addr;             /* The advertised address;
@@ -89,21 +90,21 @@
   TAILQ_ENTRY(nr_ice_candidate_) entry_comp;
 };
 
 extern char *nr_ice_candidate_type_names[];
 
 
 int nr_ice_candidate_create(struct nr_ice_ctx_ *ctx,char *label, nr_ice_component *component, nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp);
 int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg);
 int nr_ice_candidate_process_stun(nr_ice_candidate *cand, UCHAR *msg, int len, nr_transport_addr *faddr);
 int nr_ice_candidate_destroy(nr_ice_candidate **candp);
-void nr_ice_candidate_destroy_cb(int s, int h, void *cb_arg);
+void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg);
 int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen);
 int nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *attr,nr_ice_media_stream *stream,nr_ice_candidate **candp);
 int nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx *ctx,char *label, nr_ice_component *comp,nr_transport_addr *addr, nr_ice_candidate **candp);
 int nr_ice_candidate_compute_priority(nr_ice_candidate *cand);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.c src/ice/ice_candidate_pair.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_candidate_pair.c	2012-10-06 08:30:22.000000000 -0700
@@ -37,21 +37,21 @@
 #include <assert.h>
 #include <string.h>
 #include <nr_api.h>
 #include "ice_ctx.h"
 #include "ice_util.h"
 #include "ice_codeword.h"
 #include "stun.h"
 
 static char *nr_ice_cand_pair_states[]={"UNKNOWN","FROZEN","WAITING","IN_PROGRESS","FAILED","SUCCEEDED","CANCELLED"};
 
-static void nr_ice_candidate_pair_restart_stun_controlled_cb(int s, int how, void *cb_arg);
+static void nr_ice_candidate_pair_restart_stun_controlled_cb(NR_SOCKET s, int how, void *cb_arg);
 static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair,
   nr_ice_candidate *lcand, nr_ice_candidate *rcand);
 
 int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp)
   {
     nr_ice_cand_pair *pair=0;
     UINT8 o_priority, a_priority;
     char *lufrag,*rufrag;
     char *lpwd,*rpwd;
     char *l2ruser=0,*r2lpass=0;
@@ -61,21 +61,21 @@
     UINT8 t_priority;
 
     if(!(pair=RCALLOC(sizeof(nr_ice_cand_pair))))
       ABORT(R_NO_MEMORY);
     
     pair->pctx=pctx;
     
     nr_ice_candidate_pair_compute_codeword(pair,lcand,rcand);
     
     if(r=nr_concat_strings(&pair->as_string,pair->codeword,"|",lcand->addr.as_string,"|",
-         rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",0))
+        rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")", NULL))
       ABORT(r);
 
     nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
     pair->local=lcand;
     pair->remote=rcand;
 
     /* Priority computation S 5.7.2 */
     if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_OFFERER)
     {
       assert(!(pctx->ctx->flags & NR_ICE_CTX_FLAGS_ANSWERER));
@@ -87,21 +87,21 @@
       o_priority=rcand->priority;
       a_priority=lcand->priority;
     }
     pair->priority=(MIN(o_priority, a_priority))<<32 | 
       (MAX(o_priority, a_priority))<<1 | (o_priority > a_priority?0:1);
     
     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Pairing candidate %s (%x):%s (%x) priority=%llu (%llx) codeword=%s",pctx->ctx->label,lcand->addr.as_string,lcand->priority,rcand->addr.as_string,rcand->priority,pair->priority,pair->priority,pair->codeword);
 
     /* Foundation */
     if(r=nr_concat_strings(&pair->foundation,lcand->foundation,"|",
-      rcand->foundation,0))
+      rcand->foundation,NULL))
       ABORT(r);
 
 
     /* OK, now the STUN data */
     lufrag=lcand->stream->ufrag?lcand->stream->ufrag:pctx->ctx->ufrag;
     lpwd=lcand->stream->pwd?lcand->stream->pwd:pctx->ctx->pwd;
     rufrag=rcand->stream->ufrag?rcand->stream->ufrag:pctx->peer_ufrag;
     rpwd=rcand->stream->pwd?rcand->stream->pwd:pctx->peer_pwd;
 
 
@@ -110,39 +110,39 @@
 
     /* Make a bogus candidate to compute a theoretical peer reflexive
      * priority per S 7.1.1.1 */
     memcpy(&tmpcand, lcand, sizeof(tmpcand));
     tmpcand.type = PEER_REFLEXIVE;
     if (r=nr_ice_candidate_compute_priority(&tmpcand))
       ABORT(r);
     t_priority = tmpcand.priority;
 
     /* Our sending context */
-    if(r=nr_concat_strings(&l2ruser,lufrag,":",rufrag,0))
+    if(r=nr_concat_strings(&l2ruser,lufrag,":",rufrag,NULL))
       ABORT(r);
     if(r=nr_stun_client_ctx_create(pair->as_string,
       lcand->osock,
       &rcand->addr,RTO,&pair->stun_client))
       ABORT(r);
     if(!(pair->stun_client->params.ice_binding_request.username=r_strdup(l2ruser)))
       ABORT(R_NO_MEMORY);
     if(r=r_data_make(&pair->stun_client->params.ice_binding_request.password,(UCHAR *)lpwd,strlen(lpwd)))
       ABORT(r);
     pair->stun_client->params.ice_binding_request.priority=t_priority;
     pair->stun_client->params.ice_binding_request.control = pctx->controlling?
       NR_ICE_CONTROLLING:NR_ICE_CONTROLLED;
 
     pair->stun_client->params.ice_binding_request.tiebreaker=pctx->tiebreaker;
 
     /* Our receiving username/passwords. Stash these for later 
        injection into the stun server ctx*/
-    if(r=nr_concat_strings(&pair->r2l_user,rufrag,":",lufrag,0))
+    if(r=nr_concat_strings(&pair->r2l_user,rufrag,":",lufrag,NULL))
       ABORT(r);
     if(!(r2lpass=r_strdup(rpwd)))
       ABORT(R_NO_MEMORY);
     INIT_DATA(pair->r2l_pwd,(UCHAR *)r2lpass,strlen(r2lpass));
     
     *pairp=pair;
 
     _status=0;
   abort:
     RFREE(l2ruser);
@@ -178,21 +178,21 @@
 
 int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
   {
     assert(pair->state==NR_ICE_PAIR_STATE_FROZEN);
     
     nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_WAITING);
     
     return(0);
   }
 
-static void nr_ice_candidate_pair_stun_cb(int s, int how, void *cb_arg)
+static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     int r,_status;
     nr_ice_cand_pair *pair=cb_arg,*orig_pair;
     nr_ice_candidate *cand=0;
     nr_stun_message *sres;
     nr_transport_addr *request_src;
     nr_transport_addr *request_dst;
     nr_transport_addr *response_src;
     nr_transport_addr response_dst;
     nr_stun_message_attribute *attr;
@@ -457,32 +457,47 @@
   abort:
     return(_status);
  }
 
 int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state)
   {
     int r,_status;
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): setting pair %s to %s",
       pctx->label,pair->as_string,nr_ice_cand_pair_states[state]);
-    pair->state=state;
 
-    if(pctx->state!=NR_ICE_PAIR_STATE_WAITING){
+    /* NOTE: This function used to reference pctx->state instead of
+       pair->state and the assignment to pair->state was at the top
+       of this function. Because pctx->state was never changed, this seems to have
+       been a typo. The natural logic is "if the state changed
+       decrement the counter" so this implies we should be checking
+       the pair state rather than the pctx->state.
+
+       This didn't cause big problems because waiting_pairs was only
+       used for pacing, so the pacing just was kind of broken.
+       
+       This note is here as a reminder until we do more testing
+       and make sure that in fact this was a typo.
+    */
+    if(pair->state!=NR_ICE_PAIR_STATE_WAITING){
       if(state==NR_ICE_PAIR_STATE_WAITING)
         pctx->waiting_pairs++;
     }
     else{
       if(state!=NR_ICE_PAIR_STATE_WAITING)
         pctx->waiting_pairs--;
 
       assert(pctx->waiting_pairs>=0);
     }
+    pair->state=state;
+
+
     if(pair->state==NR_ICE_PAIR_STATE_FAILED){
       if(r=nr_ice_component_failed_pair(pair->remote->component, pair))
         ABORT(r);
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
@@ -505,42 +520,42 @@
         break;
       }
         
       c1=TAILQ_NEXT(c1,entry);
     }
     if(!c1) TAILQ_INSERT_TAIL(head,pair,entry);
 
     return(0);
   }
 
-void nr_ice_candidate_pair_restart_stun_nominated_cb(int s, int how, void *cb_arg)
+void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_cand_pair *pair=cb_arg;
     int r,_status;
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s):%d: Restarting pair %s as nominated",pair->pctx->label,pair->local->stream->label,pair->remote->component->component_id,pair->as_string);
 
     nr_stun_client_reset(pair->stun_client);
     pair->stun_client->params.ice_binding_request.control=NR_ICE_CONTROLLING;
 
     if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_USE_CANDIDATE,nr_ice_candidate_pair_stun_cb,pair))
       ABORT(r);
 
     if(r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))
       ABORT(r);
 
     _status=0;
   abort:
     return;
   }
 
-static void nr_ice_candidate_pair_restart_stun_controlled_cb(int s, int how, void *cb_arg)
+static void nr_ice_candidate_pair_restart_stun_controlled_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_cand_pair *pair=cb_arg;
     int r,_status;
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s):%d: Restarting pair %s as CONTROLLED",pair->pctx->label,pair->local->stream->label,pair->remote->component->component_id,pair->as_string);
 
     nr_stun_client_reset(pair->stun_client);
     pair->stun_client->params.ice_binding_request.control=NR_ICE_CONTROLLED;
 
     if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_BINDING_REQUEST,nr_ice_candidate_pair_stun_cb,pair))
@@ -556,21 +571,21 @@
 
 
 
 static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair,
   nr_ice_candidate *lcand, nr_ice_candidate *rcand)
   {
     int r,_status;
     char *as_string=0;
 
     if(r=nr_concat_strings(&as_string,lcand->addr.as_string,"|",
-      rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",0))
+      rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",NULL))
       ABORT(r);
 
     nr_ice_compute_codeword(as_string,strlen(as_string),pair->codeword);
 
     _status=0;
       abort:
     RFREE(as_string);
 return;
   }
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.h src/ice/ice_candidate_pair.h
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_candidate_pair.h	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_candidate_pair.h	2012-10-06 08:30:22.000000000 -0700
@@ -72,18 +72,18 @@
 
 int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp);
 int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
 int nr_ice_candidate_pair_start(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
 int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state);
 int nr_ice_candidate_pair_dump_state(nr_ice_cand_pair *pair, FILE *out);
 int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair);
 int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair);
 int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
 int nr_ice_candidate_pair_insert(nr_ice_cand_pair_head *head,nr_ice_cand_pair *pair);
-void nr_ice_candidate_pair_restart_stun_nominated_cb(int s, int how, void *cb_arg);
+void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void *cb_arg);
 int nr_ice_candidate_pair_destroy(nr_ice_cand_pair **pairp);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_component.c src/ice/ice_component.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_component.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_component.c	2012-10-06 08:30:22.000000000 -0700
@@ -451,21 +451,21 @@
         if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
           *error=(r==R_NO_MEMORY)?500:400;
           ABORT(r);
         }
         if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
           r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
           *error=487;
           ABORT(R_BAD_DATA);
         }
         pcand->priority=attr->u.priority;
-        pcand->state=NR_ICE_CAND_PEER_CANDIDATE;
+        pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;;
         TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
 
         if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
              &pair)) {
           *error=(r==R_NO_MEMORY)?500:400;
           ABORT(r);
         }
         nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN);        
       
         if(r=nr_ice_candidate_pair_insert(&comp->stream->check_list,pair)) {
@@ -563,30 +563,38 @@
           break;
       }
       
       /* PAIR with each peer*/
       if(TAILQ_EMPTY(&pcomp->candidates)) {
           /* can happen if our peer proposes no (or all bogus) candidates */
           goto next_cand;
       }
       pcand=TAILQ_FIRST(&pcomp->candidates);
       while(pcand){
-        nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
-        r_log(LOG_ICE,LOG_DEBUG,"Examining peer candidate %s:%s",codeword,pcand->label);
-
-        if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
-          ABORT(r);
-        
-        if(r=nr_ice_candidate_pair_insert(&pcomp->stream->check_list,
-          pair))
-          ABORT(r);
+        /* Only pair peer candidates which have not yet been paired.
+           This allows "trickle ICE". (Not yet standardized, but
+           part of WebRTC).
+
+           TODO(ekr@rtfm.com): Add refernece to the spec when there
+           is one.
+         */
+        if (pcand->state = NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED) {
+          nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
+          r_log(LOG_ICE,LOG_DEBUG,"Examining peer candidate %s:%s",codeword,pcand->label);
+          
+          if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
+            ABORT(r);
           
+          if(r=nr_ice_candidate_pair_insert(&pcomp->stream->check_list,
+              pair))
+            ABORT(r);
+        }
         pcand=TAILQ_NEXT(pcand,entry_comp);
       }
     
       if(!pair)
         ABORT(R_INTERNAL);
 
       /* Add the stun username/password pair from the last pair (any 
          would do) to the stun contexts */
       isock=STAILQ_FIRST(&lcomp->sockets);
       while(isock){
@@ -594,20 +602,28 @@
            pair->r2l_user,&pair->r2l_pwd,nr_ice_component_stun_server_cb,pcomp))
           ABORT(r);
 
         isock=STAILQ_NEXT(isock,entry);
       }
 
     next_cand:
       lcand=TAILQ_NEXT(lcand,entry_comp);
     } 
 
+    /* Mark all peer candidates as paired */
+    pcand=TAILQ_FIRST(&pcomp->candidates);
+    while(pcand){
+      pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
+      
+      pcand=TAILQ_NEXT(pcand,entry_comp);
+    }
+
     _status=0;
   abort:
     return(_status);
   }
 
 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
   {
     int r,_status;
     int fire_cb=0;
     nr_ice_cand_pair *p2;
@@ -616,32 +632,32 @@
       fire_cb=1;
 
     /* Are we changing what the nominated pair is? */
     if(comp->nominated){
       if(comp->nominated->priority > pair->priority)
         return(0);
       r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): replacing pair %s with pair %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->as_string,pair->as_string);
     }
 
     /* Set the new nominated pair */
-    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): nominated pair is %s (0x%x)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,(int)pair);
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): nominated pair is %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,pair);
     comp->state=NR_ICE_COMPONENT_NOMINATED;
     comp->nominated=pair;
     comp->active=pair;
 
-    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling all pairs but %s (0x%x)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,(int)pair);
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling all pairs but %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,pair);
 
     /* OK, we need to cancel off everything on this component */
     p2=TAILQ_FIRST(&comp->stream->check_list);
     while(p2){
       if((p2 != pair) && (p2->remote->component->component_id == comp->component_id)){
-        r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling pair %s (0x%x)",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->as_string,(int)p2);
+        r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling pair %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->as_string,p2);
         
         if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2))
           ABORT(r);
       }
 
       p2=TAILQ_NEXT(p2,entry);
     }
     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling done",comp->stream->pctx->label,comp->stream->label,comp->component_id);
 
     if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
@@ -734,21 +750,21 @@
         ABORT(r);
     }
 
     _status=0;
   abort:
     RFREE(pairs);
     return(_status);
   }
 
 
-static void nr_ice_component_keepalive_cb(int s, int how, void *cb_arg)
+static void nr_ice_component_keepalive_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_component *comp=cb_arg;
     UINT4 keepalive_timeout;
 
     assert(comp->keepalive_ctx);
 
     if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){
       keepalive_timeout=15000; /* Default */
     }
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.c src/ice/ice_ctx.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_ctx.c	2012-10-06 08:30:22.000000000 -0700
@@ -56,21 +56,21 @@
 #include "util.h"
 
 
 int LOG_ICE = 0;
 
 static int nr_ice_random_string(char *str, int len);
 static int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out);
 #ifdef USE_TURN
 static int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out);
 #endif /* USE_TURN */
-static void nr_ice_ctx_destroy_cb(int s, int how, void *cb_arg);
+static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
 
 int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out)
   {
     int r,_status;
     nr_ice_stun_server *servers = 0;
     int i;
     NR_registry child;
     char *addr=0;
     UINT2 port;
     in_addr_t addr_int;
@@ -271,21 +271,21 @@
     *ctxp=ctx;
 
     _status=0;
   abort:
     if(_status)
       nr_ice_ctx_destroy_cb(0,0,ctx);
 
     return(_status);
   }
 
-static void nr_ice_ctx_destroy_cb(int s, int how, void *cb_arg)
+static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_ctx *ctx=cb_arg;
     nr_ice_foundation *f1,*f2;
     nr_ice_media_stream *s1,*s2;
     int i;
     nr_ice_stun_id *id1,*id2;
 
     RFREE(ctx->label);
 
     RFREE(ctx->stun_servers);
@@ -323,21 +323,21 @@
     if(!ctxp || !*ctxp)
       return(0);
 
     NR_ASYNC_SCHEDULE(nr_ice_ctx_destroy_cb,*ctxp);
 
     *ctxp=0;
     
     return(0);
   }
 
-void nr_ice_initialize_finished_cb(int s, int h, void *cb_arg)
+void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg)
   {
     nr_ice_ctx *ctx=cb_arg;
 
 /*    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Candidate %s %s",ctx->label,
       cand->label, cand->state==NR_ICE_CAND_STATE_INITIALIZED?"INITIALIZED":"FAILED");
 */
     ctx->uninitialized_candidates--;
 
     if(ctx->uninitialized_candidates==0){
       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): All candidates initialized",ctx->label);
@@ -368,21 +368,22 @@
     stream=STAILQ_FIRST(&ctx->streams);
     while(stream){
       if(r=nr_ice_media_stream_initialize(ctx,stream))
         ABORT(r);
       
       stream=STAILQ_NEXT(stream,entry);
     }
 
     if(ctx->uninitialized_candidates)
       ABORT(R_WOULDBLOCK);
-
+    
+    
     _status=0;
   abort:
     return(_status);
   }
 
 int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp)
   {
     int r,_status;
 
     if(r=nr_ice_media_stream_create(ctx,label,components,streamp))
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.h src/ice/ice_ctx.h
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_ctx.h	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_ctx.h	2012-10-06 08:30:22.000000000 -0700
@@ -92,23 +92,23 @@
   UCHAR id[12];
 
   STAILQ_ENTRY(nr_ice_stun_id_) entry;
 } nr_ice_stun_id;
 
 typedef STAILQ_HEAD(nr_ice_stun_id_head_,nr_ice_stun_id_) nr_ice_stun_id_head;
 
 struct nr_ice_ctx_ {
   UINT4 flags;
   int state;
-#define NR_ICE_STATE_CREATED      1
-#define NR_ICE_STATE_INITIALIZING 2
-#define NR_ICE_STATE_INITIALIZED  3
+#define NR_ICE_STATE_CREATED          1
+#define NR_ICE_STATE_INITIALIZING     2
+#define NR_ICE_STATE_INITIALIZED      3
   char *label;
   
   char *ufrag;
   char *pwd;
 
   UINT4 Ta;
 
   nr_ice_stun_server *stun_servers;           /* The list of stun servers */
   int stun_server_ct;
   nr_ice_turn_server *turn_servers;           /* The list of turn servers */
@@ -133,21 +133,21 @@
 
 int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp);
 #define NR_ICE_CTX_FLAGS_OFFERER                           1
 #define NR_ICE_CTX_FLAGS_ANSWERER                          (1<<1)
 #define NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION             (1<<2)
 #define NR_ICE_CTX_FLAGS_LITE                              (1<<3)
 
 int nr_ice_ctx_destroy(nr_ice_ctx **ctxp);
 int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg);
 int nr_ice_add_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand);
-void nr_ice_initialize_finished_cb(int s, int h, void *cb_arg);
+void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg);
 int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp);
 int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp);
 int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);
 int nr_ice_ctx_is_known_id(nr_ice_ctx *ctx, UCHAR id[12]);
 int nr_ice_ctx_remember_id(nr_ice_ctx *ctx, nr_stun_message *msg);
 int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx);
 
 extern int LOG_ICE;
 
 #ifdef __cplusplus
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.c src/ice/ice_media_stream.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_media_stream.c	2012-10-06 08:30:22.000000000 -0700
@@ -35,21 +35,21 @@
 static char *RCSSTRING __UNUSED__="$Id: ice_media_stream.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
 
 #include <string.h>
 #include <assert.h>
 #include <nr_api.h>
 #include <r_assoc.h>
 #include <async_timer.h>
 #include "ice_ctx.h"
 
 static char *nr_ice_media_stream_states[]={"INVALID",
-  "FROZEN","ACTIVE","COMPLETED","FAILED"
+  "UNPAIRED","FROZEN","ACTIVE","COMPLETED","FAILED"
 };
 
 int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
 
 int nr_ice_media_stream_create(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp)
   {
     int r,_status;
     nr_ice_media_stream *stream=0;
     nr_ice_component *comp=0;
     int i;
@@ -66,29 +66,29 @@
     for(i=0;i<components;i++){
       /* component-id must be > 0, so increment by 1 */
       if(r=nr_ice_component_create(stream, i+1, &comp))
         ABORT(r);
 
     }
 
     TAILQ_INIT(&stream->check_list);
 
     stream->component_ct=components;
-    
+    stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED;
     *streamp=stream;
 
     _status=0;
   abort:
     if(_status){
       nr_ice_media_stream_destroy(&stream);
     }
-    return(_status);            
+    return(_status);
   }
 
 int nr_ice_media_stream_destroy(nr_ice_media_stream **streamp)
   {
     nr_ice_media_stream *stream;
     nr_ice_component *c1,*c2;
     nr_ice_cand_pair *p1,*p2;
     if(!streamp || !*streamp)
       return(0);
 
@@ -200,85 +200,148 @@
       if(attrs){
         for(index=0;index<attrct;index++){
           RFREE(attrs[index]);
         }
         RFREE(attrs);
       }
     }
     return(_status);
   }
 
+
+/* Get a default candidate per 4.1.4 */
+int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp)
+  {
+    int _status;
+    nr_ice_component *comp;
+    nr_ice_candidate *cand;
+    nr_ice_candidate *best_cand = NULL;
+
+    comp=STAILQ_FIRST(&stream->components);
+    while(comp){
+      if (comp->component_id == component)
+        break;
+      
+      comp=STAILQ_NEXT(comp,entry);
+    }
+    
+    if (!comp)
+      ABORT(R_NOT_FOUND);
+
+    /* We have the component. Now find the "best" candidate, making 
+       use of the fact that more "reliable" candidate types have
+       higher numbers. So, we sort by type and then priority within
+       type
+    */
+    cand=TAILQ_FIRST(&comp->candidates);
+    while(cand){
+      if (!best_cand) {
+        best_cand = cand;
+      }
+      else {
+        if (best_cand->type < cand->type) {
+          best_cand = cand;
+        } else if (best_cand->type == cand->type) { 
+          if (best_cand->priority < cand->priority)
+            best_cand = cand;
+        }
+      }
+
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+    
+    /* No candidates */
+    if (!best_cand)
+      ABORT(R_NOT_FOUND);
+
+    *candp = best_cand;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
 int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream)
   {
     int r,_status;
     nr_ice_component *pcomp,*lcomp;
 
     pcomp=STAILQ_FIRST(&pstream->components);
     lcomp=STAILQ_FIRST(&lstream->components);
     while(pcomp){
       if(r=nr_ice_component_pair_candidates(pctx,lcomp,pcomp))
         ABORT(r);
-      
+
       lcomp=STAILQ_NEXT(lcomp,entry);
       pcomp=STAILQ_NEXT(pcomp,entry);
     };
 
+    if (pstream->ice_state == NR_ICE_MEDIA_STREAM_UNPAIRED) {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): unfreezing stream %s",pstream->pctx->label,pstream->label);
+      pstream->ice_state = NR_ICE_MEDIA_STREAM_CHECKS_FROZEN;
+    }
+
     _status=0;
   abort:
     return(_status);
   }
 
 /* S 5.8 -- run the highest priority WAITING pair or if not available
    FROZEN pair */
-static void nr_ice_media_stream_check_timer_cb(int s, int h, void *cb_arg)
+static void nr_ice_media_stream_check_timer_cb(NR_SOCKET s, int h, void *cb_arg)
   {
     int r,_status;
     nr_ice_media_stream *stream=cb_arg;
     nr_ice_cand_pair *pair;
     int timer_val;
 
     assert(stream->pctx->active_streams!=0);
 
     timer_val=stream->pctx->ctx->Ta*stream->pctx->active_streams;
 
+    if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED) {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): bogus state for stream %s",stream->pctx->label,stream->label);
+    }
     assert(stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED);
     
     r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): check timer expired for media stream %s",stream->pctx->label,stream->label);
     stream->timer=0;
 
-
     /* Find the highest priority WAITING check and move it to RUNNING */
     pair=TAILQ_FIRST(&stream->check_list);
     while(pair){
       if(pair->state==NR_ICE_PAIR_STATE_WAITING)
         break;
       pair=TAILQ_NEXT(pair,entry);
     }
 
     /* Hmmm... No WAITING. Let's look for FROZEN */
     if(!pair){
       pair=TAILQ_FIRST(&stream->check_list);
-      
+
       while(pair){
         if(pair->state==NR_ICE_PAIR_STATE_FROZEN){
           if(r=nr_ice_candidate_pair_unfreeze(stream->pctx,pair))
             ABORT(r);
           break;
         }
         pair=TAILQ_NEXT(pair,entry);
       }
     }
 
     if(pair){
       nr_ice_candidate_pair_start(pair->pctx,pair); /* Ignore failures */
       NR_ASYNC_TIMER_SET(timer_val,nr_ice_media_stream_check_timer_cb,cb_arg,&stream->timer);
     }
+    /* TODO(ekr@rtfm.com): Report on the special case where there are no checks to
+       run at all */
     _status=0;
   abort:
     return;
   }
 
 
 /* Start checks for this media stream (aka check list) */
 int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
   {
     assert(stream->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FROZEN);
@@ -476,21 +539,23 @@
     /* All done... */
     r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/ICE-STREAM(%s): all components have nominated candidate pairs",stream->pctx->label,stream->label);
     nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED);
     
     /* Cancel our timer */
     if(stream->timer){
       NR_async_timer_cancel(stream->timer);
       stream->timer=0;
     }
 
-    stream->pctx->handler->vtbl->stream_ready(stream->pctx->handler->obj,stream->local_stream);
+    if (stream->pctx->handler) {
+      stream->pctx->handler->vtbl->stream_ready(stream->pctx->handler->obj,stream->local_stream);
+    }
 
     /* Now tell the peer_ctx that we're done */
     if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream))
       ABORT(r);
     
   done:
     _status=0;
   abort:
     return(_status);
   }
@@ -515,21 +580,23 @@
       
       p2=TAILQ_NEXT(p2,entry);
     }
 
     /* Cancel our timer */
     if(stream->timer){
       NR_async_timer_cancel(stream->timer);
       stream->timer=0;
     }
 
-    stream->pctx->handler->vtbl->stream_failed(stream->pctx->handler->obj,stream->local_stream);
+    if (stream->pctx->handler) {
+      stream->pctx->handler->vtbl->stream_failed(stream->pctx->handler->obj,stream->local_stream);
+    }
 
     /* Now tell the peer_ctx that we're done */
     if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream))
       ABORT(r);
 
     _status=0;
   abort:
     return(_status);
   }
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.h src/ice/ice_media_stream.h
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_media_stream.h	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_media_stream.h	2012-10-06 08:30:22.000000000 -0700
@@ -45,40 +45,43 @@
   struct nr_ice_peer_ctx_ *pctx;
 
   struct nr_ice_media_stream_ *local_stream; /* used when this is a peer */
   int component_ct;
   nr_ice_component_head components;
 
   char *ufrag;    /* ICE username */
   char *pwd;    /* ICE password */
 
   int ice_state;
-#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN      1
-#define NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE      2
-#define NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED   3
-#define NR_ICE_MEDIA_STREAM_CHECKS_FAILED      4
+
+#define NR_ICE_MEDIA_STREAM_UNPAIRED           1
+#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN      2
+#define NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE      3
+#define NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED   4
+#define NR_ICE_MEDIA_STREAM_CHECKS_FAILED      5
 
   nr_ice_cand_pair_head check_list;
   void *timer;  /* Check list periodic timer */
 
 //  nr_ice_cand_pair_head valid_list;
-  
+
   STAILQ_ENTRY(nr_ice_media_stream_) entry;
 };
 
 typedef STAILQ_HEAD(nr_ice_media_stream_head_,nr_ice_media_stream_) nr_ice_media_stream_head;
 
 int nr_ice_media_stream_create(struct nr_ice_ctx_ *ctx,char *label, int components, nr_ice_media_stream **streamp);
 int nr_ice_media_stream_destroy(nr_ice_media_stream **streamp);
 int nr_ice_media_stream_finalize(nr_ice_media_stream *lstr,nr_ice_media_stream *rstr);
 int nr_ice_media_stream_initialize(struct nr_ice_ctx_ *ctx, nr_ice_media_stream *stream);
 int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attrsp,int *attrctp);
+int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp);
 int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream);
 int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
 int nr_ice_media_stream_unfreeze_pairs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
 int nr_ice_media_stream_unfreeze_pairs_foundation(nr_ice_media_stream *stream, char *foundation);
 int nr_ice_media_stream_dump_state(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream,FILE *out);
 int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component);
 int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component);
 int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
 int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp);
 int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx,nr_ice_media_stream *str, int component, UCHAR *data, int len);
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_parser.c src/ice/ice_parser.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_parser.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_parser.c	2012-10-06 08:30:22.000000000 -0700
@@ -35,20 +35,21 @@
 static char *RCSSTRING __UNUSED__="$Id: ice_parser.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
 
 #include <csi_platform.h>
 #include <sys/types.h>
 #ifdef WIN32
 #include <winsock2.h>
 #else
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <strings.h>
 #endif
 #include <string.h>
 #include <assert.h>
 #include <ctype.h>
 #include "nr_api.h"
 #include "ice_ctx.h"
 #include "ice_candidate.h"
 #include "ice_reg.h"
 
 static void
@@ -125,21 +126,21 @@
     char *rel_addr=0;
 
     if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
         ABORT(R_NO_MEMORY);
 
     if(!(cand->label=r_strdup(orig)))
         ABORT(R_NO_MEMORY);
 
     cand->ctx=ctx;
     cand->isock=0;
-    cand->state=NR_ICE_CAND_PEER_CANDIDATE;
+    cand->state=NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED;
     cand->stream=stream;
     skip_whitespace(&str);
 
     /* Candidate attr */
     if (strncasecmp(str, "candidate:", 10))
         ABORT(R_BAD_DATA);
 
     fast_forward(&str, 10);
     if (*str == '\0')
         ABORT(R_BAD_DATA);
@@ -311,26 +312,31 @@
         /* it's expected to be at EOD at this point */
 
         break;
     default:
         ABORT(R_INTERNAL);
         break;
     }
 
     skip_whitespace(&str);
 
-    assert(strlen(str) == 0);
-
+    /* This used to be an assert, but we don't want to exit on invalid
+       remote data */
+    if (strlen(str) != 0) {
+      ABORT(R_BAD_DATA);
+    }
+      
     *candp=cand;
 
     _status=0;
   abort:
+    /* TODO(ekr@rtfm.com): Fix memory leak if we have a parse error */
     if (_status)
         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Error parsing attribute: %s",ctx->label,orig);
 
     RFREE(connection_address);
     RFREE(rel_addr);
     return(_status);
 }
 
 
 int
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.c src/ice/ice_peer_ctx.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_peer_ctx.c	2012-10-06 08:30:22.000000000 -0700
@@ -35,33 +35,35 @@
 static char *RCSSTRING __UNUSED__="$Id: ice_peer_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
 
 #include <string.h>
 #include <assert.h>
 #include <nr_api.h>
 #include "ice_ctx.h"
 #include "ice_peer_ctx.h"
 #include "nr_crypto.h"
 #include "async_timer.h"
 
-static void nr_ice_peer_ctx_destroy_cb(int s, int how, void *cb_arg);
+static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
+static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct);
+static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate);
 
 int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp)
   {
     int r,_status;
     nr_ice_peer_ctx *pctx=0;
 
     if(!(pctx=RCALLOC(sizeof(nr_ice_peer_ctx))))
       ABORT(R_NO_MEMORY);
 
     if(!(pctx->label=r_strdup(label)))
       ABORT(R_NO_MEMORY);
-    
+
     pctx->ctx=ctx;
     pctx->handler=handler;
 
     /* Decide controlling vs. controlled */
     if(ctx->flags & NR_ICE_CTX_FLAGS_LITE){
       if(pctx->peer_lite){
         r_log(LOG_ICE,LOG_ERR,"Both sides are ICE-Lite");
         ABORT(R_BAD_DATA);
       }
         
@@ -88,85 +90,177 @@
       nr_ice_peer_ctx_destroy_cb(0,0,pctx);
     }
     return(_status);
   }
 
 
 
 int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct)
   {
     nr_ice_media_stream *pstream=0;
-    nr_ice_candidate *cand=0;
     nr_ice_component *comp,*comp2;
     int r,_status;
-    int i,j;
 
-    /* Note: use component_ct from our own stream since components other
-       than this offered by the other side are unusable */
+    /*
+      Note: use component_ct from our own stream since components other
+      than this offered by the other side are unusable */
     if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,stream->component_ct,&pstream))
       ABORT(r);
-    
-    /* Match up the local and remote components */ 
+
+    /* Match up the local and remote components */
     comp=STAILQ_FIRST(&stream->components);
     comp2=STAILQ_FIRST(&pstream->components);
     while(comp){
       comp2->local_component=comp;
 
       comp=STAILQ_NEXT(comp,entry);
       comp2=STAILQ_NEXT(comp2,entry);
     }
-        
 
-    pstream->ice_state=NR_ICE_MEDIA_STREAM_CHECKS_FROZEN;
     pstream->local_stream=stream;
     pstream->pctx=pctx;
 
+    if (r=nr_ice_peer_ctx_parse_stream_attributes_int(pctx,stream,pstream,attrs,attr_ct))
+      ABORT(r);
+
+
+    STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct)
+  {
+    int r;
+    int i;
+
     for(i=0;i<attr_ct;i++){
       if(!strncmp(attrs[i],"ice-",4)){
-        if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i]))
+        if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) {
+          r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus ICE attribute",pctx->ctx->label,pctx->label);
           continue;
-        continue;
+        }
       }
-        
-      if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,attrs[i],pstream,&cand))
-        continue;
-      if(cand->component_id-1>=pstream->component_ct){
-        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified too many components",pctx->ctx->label,pctx->label);
-        continue;
+      else if (!strncmp(attrs[i],"candidate",9)){
+        if(r=nr_ice_ctx_parse_candidate(pctx,pstream,attrs[i])) {
+          r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus candidate",pctx->ctx->label,pctx->label);
+          continue;
+        }
+      }
+      else {
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus attribute",pctx->ctx->label,pctx->label);
       }
+    }
 
-      /* Not the fastest way to find a component, but it's what we got */
-      j=1;
-      for(comp=STAILQ_FIRST(&pstream->components);comp;comp=STAILQ_NEXT(comp,entry)){
-        if(j==cand->component_id)
-          break;
+    /* Doesn't fail because we just skip errors */
+    return(0);
+  }
 
-        j++;
-      }
-      
-      if(!comp){
-        r_log(LOG_ICE,LOG_ERR,"Peer answered with more components than we offered");
-        ABORT(R_BAD_DATA);
-      }
-      
-      cand->component=comp;
+static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate)
+  {
+    nr_ice_candidate *cand=0;
+    nr_ice_component *comp;
+    int j;
+    int r, _status;
 
-      TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp);
+    if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,candidate,pstream,&cand))
+      ABORT(r);
+    if(cand->component_id-1>=pstream->component_ct){
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified too many components",pctx->ctx->label,pctx->label);
+      ABORT(R_BAD_DATA);
     }
 
-    STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry);
+    /* Not the fastest way to find a component, but it's what we got */
+    j=1;
+    for(comp=STAILQ_FIRST(&pstream->components);comp;comp=STAILQ_NEXT(comp,entry)){
+      if(j==cand->component_id)
+        break;
+
+      j++;
+    }
+
+    if(!comp){
+      r_log(LOG_ICE,LOG_ERR,"Peer answered with more components than we offered");
+      ABORT(R_BAD_DATA);
+    }
+
+    cand->component=comp;
+
+    TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp);
 
     _status=0;
-  abort:
+ abort:
+    if (_status) {
+      nr_ice_candidate_destroy(&cand);
+    }
     return(_status);
   }
 
+
+
+int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate)
+  {
+    /* First need to find the stream. Because we don't have forward pointers,
+       iterate through all the peer streams to find one that matches us */
+    nr_ice_media_stream *pstream;
+    int r,_status;
+    int needs_pairing = 0;
+
+    pstream=STAILQ_FIRST(&pctx->peer_streams);
+    while(pstream) {
+      if (pstream->local_stream == stream)
+        break;
+      
+      pstream = STAILQ_NEXT(pstream, entry);
+    }
+    if (!pstream) {
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label);
+      ABORT(R_NOT_FOUND);
+    }
+
+    switch(pstream->ice_state) {
+      case NR_ICE_MEDIA_STREAM_UNPAIRED:
+        break;
+      case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN:
+      case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE:
+        needs_pairing = 1;
+        break;
+      default:
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) tried to trickle ICE in inappropriate state %d",pctx->ctx->label,pctx->label,stream->label,pstream->ice_state);
+        ABORT(R_ALREADY);
+        break;
+    }
+
+    if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate)){
+      ABORT(r);
+    }
+
+    /* If ICE is running (i.e., we are in FROZEN or ACTIVE states)
+       then we need to pair this new candidate. For now we
+       just re-pair the stream which is inefficient but still
+       fine because we suppress duplicate pairing */
+    if (needs_pairing) {
+      if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) {
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) failed to pair trickle ICE candidates",pctx->ctx->label,pctx->label,stream->label);
+        ABORT(r);
+      }
+    }
+
+    _status =0;
+ abort:
+    return(_status);
+
+  }
+
+
 int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
   {
     nr_ice_media_stream *stream;
     int r,_status;
 
     if(STAILQ_EMPTY(&pctx->peer_streams)) {
         r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) received no media stream attribributes",pctx->ctx->label,pctx->label);
         ABORT(R_FAILED);
     }
 
@@ -177,21 +271,21 @@
         ABORT(r);
 
       stream=STAILQ_NEXT(stream,entry);
     }   
 
     _status=0;
   abort:
     return(_status);
   }
 
-static void nr_ice_peer_ctx_destroy_cb(int s, int how, void *cb_arg)
+static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_peer_ctx *pctx=cb_arg;
     nr_ice_media_stream *str1,*str2;
 
     RFREE(pctx->label);
     RFREE(pctx->peer_ufrag);
     RFREE(pctx->peer_pwd);
     
     STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2){
       STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry);
@@ -199,44 +293,79 @@
     }
 
     RFREE(pctx);
   }
 
 int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp)
   {
 
     if(!pctxp || !*pctxp)
       return(0);
-    
+
+    /* Stop calling the handler */
+    (*pctxp)->handler = 0;
+
     NR_ASYNC_SCHEDULE(nr_ice_peer_ctx_destroy_cb,*pctxp);
 
     *pctxp=0;
 
     return(0);
   }
 
+
 /* Start the checks for the first media stream (S 5.7)
    The rest remain FROZEN */
 int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx)
   {
+    return nr_ice_peer_ctx_start_checks2(pctx, 0);
+  }
+
+/* Start checks for some media stream.
+
+   If allow_non_first == 0, then we only look at the first stream,
+   which is 5245-complaint.
+
+   If allow_non_first == 1 then we find the first non-empty stream
+   This is not compliant with RFC 5245 but is necessary to make trickle ICE
+   work plausibly
+*/
+int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first)
+  {
     int r,_status;
     nr_ice_media_stream *stream;
 
     stream=STAILQ_FIRST(&pctx->peer_streams);
     if(!stream)
       ABORT(R_FAILED);
 
+    while (stream) {
+      if(!TAILQ_EMPTY(&stream->check_list))
+        break;
+
+      if(!allow_non_first){
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label);
+        ABORT(R_FAILED);
+      }
+
+      stream=STAILQ_NEXT(stream, entry);
+    }
+
+    if (!stream) {
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label);
+      ABORT(R_NOT_FOUND);
+    }
+
     if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) {
-        if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream))
-          ABORT(r);
-        if(r=nr_ice_media_stream_start_checks(pctx,stream))
-          ABORT(r);
+      if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream))
+        ABORT(r);
+      if(r=nr_ice_media_stream_start_checks(pctx,stream))
+        ABORT(r);
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
 #ifndef NDEBUG
 int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out)
   {
@@ -253,26 +382,28 @@
       stream=STAILQ_NEXT(stream,entry);
     }
     fprintf(out,"==========================================\n");
 
     _status=0;
   abort:
     return(_status);
   }
 #endif
 
-static void nr_ice_peer_ctx_fire_done(int s, int how, void *cb_arg)
+static void nr_ice_peer_ctx_fire_done(NR_SOCKET s, int how, void *cb_arg)
   {
     nr_ice_peer_ctx *pctx=cb_arg;
 
     /* Fire the handler callback to say we're done */
-    pctx->handler->vtbl->ice_completed(pctx->handler->obj, pctx);
+    if (pctx->handler) {
+      pctx->handler->vtbl->ice_completed(pctx->handler->obj, pctx);
+    }
   }
 
 
 /* OK, a stream just went ready. Examine all the streams to see if we're
    maybe miraculously done */
 int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
   {
     int _status;
     nr_ice_media_stream *str;
     int failed=0;
@@ -365,21 +496,24 @@
         NR_TRANSPORT_ADDR_CMP_MODE_ALL))
         break;
 
       cand=TAILQ_NEXT(cand,entry_comp);
     }
 
     if(!cand)
       ABORT(R_REJECTED);
 
     /* OK, there's a match. Call the handler */
-    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Delivering data", pctx->label);
 
-    pctx->handler->vtbl->msg_recvd(pctx->handler->obj,
-      pctx,comp->stream,comp->component_id,data,len);
+    if (pctx->handler) {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Delivering data", pctx->label);
+
+      pctx->handler->vtbl->msg_recvd(pctx->handler->obj,
+        pctx,comp->stream,comp->component_id,data,len);
+    }
 
     _status=0;
   abort:
     return(_status);
   }
 
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.h src/ice/ice_peer_ctx.h
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_peer_ctx.h	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_peer_ctx.h	2012-10-06 08:30:22.000000000 -0700
@@ -33,23 +33,21 @@
 
 
 #ifndef _ice_peer_ctx_h
 #define _ice_peer_ctx_h
 #ifdef __cplusplus
 using namespace std;
 extern "C" {
 #endif /* __cplusplus */
 
 struct nr_ice_peer_ctx_ {
-  int state;
   char *label;
-  
   nr_ice_ctx *ctx;
   nr_ice_handler *handler;
 
   UCHAR controlling; /* 1 for controlling, 0 for controlled */
   UINT8 tiebreaker;
 
   char *peer_ufrag;
   char *peer_pwd;
   int peer_lite;
   int peer_ice_mismatch;
@@ -59,23 +57,26 @@
   int waiting_pairs;
 
   STAILQ_ENTRY(nr_ice_peer_ctx_) entry;
 };
 
 typedef STAILQ_HEAD(nr_ice_peer_ctx_head_, nr_ice_peer_ctx_) nr_ice_peer_ctx_head;
 
 int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp);
 int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp);
 int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct);
+int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *cand);
+
 int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx);
 int nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int attr_ct);
 int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx);
+int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first);
 int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out);
 int nr_ice_peer_ctx_log_state(nr_ice_peer_ctx *pctx);
 int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
 int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp);
 int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_socket.c src/ice/ice_socket.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/ice/ice_socket.c	2012-09-16 16:26:08.000000000 -0700
+++ src/ice/ice_socket.c	2012-10-06 08:30:22.000000000 -0700
@@ -216,28 +216,34 @@
       RFREE(s1);
     }
 
     RFREE(isock);
     
     return(0);
   }
 
 int nr_ice_socket_close(nr_ice_socket *isock)
   {
+#ifdef NR_SOCKET_IS_VOID_PTR
+    NR_SOCKET fd=NULL;
+    NR_SOCKET no_socket = NULL;
+#else
     NR_SOCKET fd=-1;
+    NR_SOCKET no_socket = -1;
+#endif
 
     if (!isock||!isock->sock)
       return(0);
 
     nr_socket_getfd(isock->sock,&fd);
     assert(isock->sock!=0);
-    if(fd!=-1){
+    if(fd != no_socket){
       NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ);
       NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE);
       nr_socket_destroy(&isock->sock);
     }
     
     return(0);
   }
 
 int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle)
   {
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/net/nr_socket.h src/net/nr_socket.h
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/net/nr_socket.h	2012-09-16 16:26:09.000000000 -0700
+++ src/net/nr_socket.h	2012-10-06 08:30:22.000000000 -0700
@@ -38,21 +38,23 @@
 #include <sys/types.h>
 #ifdef WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #else
 #include <sys/socket.h>
 #endif
 
 #include "transport_addr.h"
 
-#ifdef WIN32
+#ifdef __cplusplus
+#define restrict
+#elif defined(WIN32)
 #define restrict __restrict
 #endif
 
 typedef struct nr_socket_vtbl_ {
   int (*destroy)(void **obj);
   int (*ssendto)(void *obj,const void *msg, size_t len, int flags,
     nr_transport_addr *addr);
   int (*srecvfrom)(void *obj,void * restrict buf, size_t maxlen, size_t *len, int flags,
     nr_transport_addr *addr);
   int (*getfd)(void *obj, NR_SOCKET *fd);
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/net/transport_addr_reg.c src/net/transport_addr_reg.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/net/transport_addr_reg.c	2012-09-16 16:26:09.000000000 -0700
+++ src/net/transport_addr_reg.c	2012-10-06 08:30:22.000000000 -0700
@@ -29,25 +29,27 @@
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 
 
 static char *RCSSTRING __UNUSED__="$Id: transport_addr_reg.c,v 1.2 2008/04/28 17:59:03 ekr Exp $";
 
 #include <csi_platform.h>
 #include <stdio.h>
+#include <string.h>
 #include <memory.h>
 #include <sys/types.h>
 #ifdef WIN32
 #include <winsock2.h>
 #else
+#include <strings.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
 #include <assert.h>
 #include "nr_api.h"
 #include "transport_addr.h"
 #include "transport_addr_reg.h"
 
@@ -83,20 +85,22 @@
 
     if ((r=NR_reg_get2_uint2(prefix, "port", &port))) {
         if (r != R_NOT_FOUND)
             ABORT(r);
         port = 0;
     }
 
     if ((r=NR_reg_alloc2_string(prefix, "protocol", &protocol))) {
         if (r != R_NOT_FOUND)
             ABORT(r);
+        p = IPPROTO_UDP;
+
         protocol = 0;
     }
     else {
         if (!strcasecmp("tcp", protocol))
             p = IPPROTO_TCP;
         else if (!strcasecmp("udp", protocol))
             p = IPPROTO_UDP;
         else
             ABORT(R_BAD_DATA);
     }
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/addrs.c src/stun/addrs.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/addrs.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/addrs.c	2012-10-06 09:42:43.000000000 -0700
@@ -46,20 +46,22 @@
 #include <sys/sysctl.h>
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/syslog.h>
 #include <net/if.h>
 #ifndef LINUX
 #include <net/if_var.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <sys/sockio.h>
+#else
+#include <linux/if.h>
 #endif
 #include <net/route.h>
 
 /* IP */
 #include <netinet/in.h>
 #ifdef LINUX
 #include "sys/ioctl.h"
 #else
 #include <netinet/in_var.h>
 #endif
@@ -105,20 +107,23 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <err.h>
 
 static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
 static int stun_grab_addrs(char *name, int addrcount,
                struct ifa_msghdr *ifam,
                nr_transport_addr addrs[], int maxaddrs, int *count);
+static int
+nr_stun_is_duplicate_addr(nr_transport_addr addrs[], int count, nr_transport_addr *addr);
+
 
 /*
  * Expand the compacted form of addresses as returned via the
  * configuration read via sysctl().
  */
 #define ROUNDUP(a) \
     ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
 static void
@@ -135,21 +140,21 @@
             continue;
         rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
         ADVANCE(cp, sa);
     }
 }
 
 static int
 stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_transport_addr addrs[], int maxaddrs, int *count)
 {
     int r,_status;
-    NR_SOCKET s = -1;
+    int s = -1;
     struct ifreq ifr;
     struct rt_addrinfo info;
     struct sockaddr_in *sin;
 
     ifr.ifr_addr.sa_family = AF_INET;
     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
 
     if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
       r_log(NR_LOG_STUN, LOG_WARNING, "unable to obtain addresses from socket");
       ABORT(R_FAILED);
@@ -180,21 +185,20 @@
         addrcount--;
 
         if (*count >= maxaddrs) {
             r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of entries", maxaddrs, maxaddrs+addrcount);
             break;
         }
 
         ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
     }
 
-
     _status = 0;
   abort:
     if (s != -1) close(s);
     return _status;
 }
 
 static int
 stun_get_mib_addrs(nr_transport_addr addrs[], int maxaddrs, int *count)
 {
     int _status;
@@ -551,44 +555,48 @@
 #else
 
 static int
 stun_get_siocgifconf_addrs(nr_transport_addr addrs[], int maxaddrs, int *count)
 {
    struct ifconf ifc;
    int _status;
    int s = socket( AF_INET, SOCK_DGRAM, 0 );
    int len = 100 * sizeof(struct ifreq);
    int r;
+   int e;
+   char *ptr;
+   int tl;
+   int n;
+   struct ifreq ifr2;
 
    char buf[ len ];
 
    ifc.ifc_len = len;
    ifc.ifc_buf = buf;
 
-   int e = ioctl(s,SIOCGIFCONF,&ifc);
-   char *ptr = buf;
-   int tl = ifc.ifc_len;
-   int n=0;
+   e = ioctl(s,SIOCGIFCONF,&ifc);
+   ptr = buf;
+   tl = ifc.ifc_len;
+   n=0;
 
    while ( (tl > 0) && ( n < maxaddrs) )
    {
       struct ifreq* ifr = (struct ifreq *)ptr;
 
 #ifdef LINUX
-      int si = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr);
+      int si = sizeof(struct ifreq);
 #else
       int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr));
 #endif
       tl -= si;
       ptr += si;
 
-      struct ifreq ifr2;
       ifr2 = *ifr;
 
       e = ioctl(s,SIOCGIFADDR,&ifr2);
       if ( e == -1 )
       {
           continue;
       }
 
       //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e);
 
@@ -603,21 +611,21 @@
 
    close(s);
 
    *count = n;
 
     _status = 0;
     return _status;
 }
 #endif
 
-int
+static int
 nr_stun_is_duplicate_addr(nr_transport_addr addrs[], int count, nr_transport_addr *addr)
 {
     int i;
     int different;
 
     for (i = 0; i < count; ++i) {
         different = nr_transport_addr_cmp(&addrs[i], addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL);
         if (!different) 
             return 1;  /* duplicate */
     }
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/nr_socket_turn.c src/stun/nr_socket_turn.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/nr_socket_turn.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/nr_socket_turn.c	2012-10-06 08:30:22.000000000 -0700
@@ -246,17 +246,19 @@
     default:
         assert(0);
         break;
     }
 
     return R_FAILED;
   }
 
 static int nr_socket_turn_close(void *obj)
   {
+#ifndef NDEBUG
     nr_socket_turn *sturn=obj;
     assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+#endif
 
     return 0;
   }
 
 #endif /* USE_TURN */
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_client_ctx.c src/stun/stun_client_ctx.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_client_ctx.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/stun_client_ctx.c	2012-10-06 08:30:22.000000000 -0700
@@ -38,21 +38,22 @@
 #include <string.h>
 
 #include <nr_api.h>
 #include "stun.h"
 #include "async_timer.h"
 #include "registry.h"
 #include "stun_reg.h"
 #include "r_time.h"
 
 static int nr_stun_client_send_request(nr_stun_client_ctx *ctx);
-static void nr_stun_client_timer_expired_cb(int a, int b, void *cb_arg);
+static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg);
+static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password);
 
 int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp)
   {
     nr_stun_client_ctx *ctx=0;
     int r,_status;
 
     if ((r=nr_stun_startup()))
       ABORT(r);
 
     if(!(ctx=RCALLOC(sizeof(nr_stun_client_ctx))))
@@ -185,21 +186,21 @@
     ctx->finished_cb   = 0;
     ctx->cb_arg        = 0;
     ctx->request_ct    = 0;
     ctx->timeout_ms    = 0;
 
     ctx->state = NR_STUN_CLIENT_STATE_INITTED;
 
     return 0;
 }
 
-static void nr_stun_client_timer_expired_cb(int a, int b, void *cb_arg)
+static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg)
   {
     int _status;
     nr_stun_client_ctx *ctx=cb_arg;
     struct timeval now;
     INT8 ms_waited;
 
     /* Prevent this timer from being cancelled later */
     ctx->timer_handle=0;
 
     /* Shouldn't happen */
@@ -387,21 +388,21 @@
     }
    
     _status=0;
   abort:
     if (_status) {
       ctx->state=NR_STUN_CLIENT_STATE_FAILED;
     }
     return(_status);
   }
 
-int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password)
+static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password)
 {
     *password = (Data*)arg;
     if (!arg)
         return(R_NOT_FOUND);
     return(0);
 }
 
 int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
   {
     int r,_status;
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_codec.c src/stun/stun_codec.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_codec.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/stun_codec.c	2012-10-06 08:30:22.000000000 -0700
@@ -73,20 +73,22 @@
 static int nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data);
 static int nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data);
 
 static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars);
 
 static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
 static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
 static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
 static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
 static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
+static int
+nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data);
 
 
 int
 nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset)
 {
    UINT2 d = htons(data);
 
    if (*offset + sizeof(d) >= buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d >= %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
@@ -632,21 +634,21 @@
     }
 
     fingerprint->checksum = checksum ^ 0x5354554e;
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", fingerprint->checksum);
 
     fingerprint->valid = 1;
     return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen);
 }
 
-int
+static int
 nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
 {
     int r,_status;
     nr_stun_attr_fingerprint *fingerprint = data;
     nr_stun_message_header *header = (nr_stun_message_header*)buf;
     int length;
     UINT4 checksum;
 
     if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum)))
         ABORT(r);
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_proc.c src/stun/stun_proc.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_proc.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/stun_proc.c	2012-10-06 08:30:22.000000000 -0700
@@ -43,20 +43,22 @@
 #include <time.h>
 #else   /* UNIX */
 #include <string.h>
 #endif  /* end UNIX */
 #include <assert.h>
 
 #include "stun.h"
 #include "stun_reg.h"
 #include "registry.h"
 
+static int
+nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res);
 
 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3 */
 int
 nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg)
 {
     int _status;
     nr_stun_message_attribute *attr;
 
 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
     /* if this message was generated by an RFC 3489 impementation,
@@ -371,21 +373,21 @@
         /* nothing to check in this case */
         break;
 #endif /* USE_STUND_0_96 */
     }
 
    _status=0;
  abort:
      return _status;
 }
 
-int
+static int
 nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res)
 {
     int r,_status;
     char *realm = 0;
     char *nonce;
     UINT2 size;
 
     if ((r=NR_reg_alloc_string(NR_STUN_REG_PREF_SERVER_REALM, &realm)))
         ABORT(r);
 
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_server_ctx.c src/stun/stun_server_ctx.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_server_ctx.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/stun_server_ctx.c	2012-10-06 08:30:22.000000000 -0700
@@ -114,21 +114,21 @@
     STAILQ_INSERT_TAIL(&ctx->clients,clnt,entry);
     
     _status=0;
   abort:
     if(_status){
       nr_stun_server_destroy_client(clnt);
     }
     return(_status);
   }
 
-int nr_stun_server_get_password(void *arg, nr_stun_message *msg, Data **password)
+static int nr_stun_server_get_password(void *arg, nr_stun_message *msg, Data **password)
   {
     int _status;
     nr_stun_server_ctx *ctx = (nr_stun_server_ctx*)arg;
     nr_stun_server_client *clnt = 0;
     nr_stun_message_attribute *username_attribute;
 
     if ((nr_stun_get_message_client(ctx, msg, &clnt))) {
         if (! nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, &username_attribute)) {
            r_log(NR_LOG_STUN,LOG_NOTICE,"STUN-SERVER(%s): Missing Username",ctx->label);
            ABORT(R_NOT_FOUND);
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_util.c src/stun/stun_util.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/stun_util.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/stun_util.c	2012-10-06 08:30:22.000000000 -0700
@@ -94,21 +94,20 @@
     _status = 0;
   abort:
     return _status;
 }
 
 int
 nr_stun_find_local_addresses(nr_transport_addr addrs[], int maxaddrs, int *count)
 {
     int r,_status;
     NR_registry *children = 0;
-    int i;
 
     if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count)))
         if (r == R_NOT_FOUND)
             *count = 0;
         else
             ABORT(r);
 
     if (*count == 0) {
         if ((r=nr_stun_get_addrs(addrs, maxaddrs, 1, count)))
             ABORT(r);
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/turn_client_ctx.c src/stun/turn_client_ctx.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/stun/turn_client_ctx.c	2012-09-16 16:26:10.000000000 -0700
+++ src/stun/turn_client_ctx.c	2012-10-06 08:30:22.000000000 -0700
@@ -55,21 +55,24 @@
 };
 
 static int TURN_PHASE_MODE[NUMBER_OF_STUN_CTX] = {
     NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1,
     NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2,
     NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST
 };
 
 
 static int nr_turn_client_next_action(nr_turn_client_ctx *ctx, int stun_ctx_state);
-static void nr_turn_client_cb(int s, int how, void *cb_arg);
+static void nr_turn_client_cb(NR_SOCKET s, int how, void *cb_arg);
+static int
+nr_turn_client_prepare_start(nr_turn_client_ctx *ctx, char *username, Data *password, UINT4 bandwidth_kbps, UINT4 lifetime_secs, NR_async_cb finished_cb, void *cb_arg);
+
 
 int
 nr_turn_client_next_action(nr_turn_client_ctx *ctx, int stun_ctx_state)
 {
     int r,_status;
 
     assert(ctx->phase >= -1 && ctx->phase < NUMBER_OF_STUN_CTX);
 
     switch (ctx->state) {
     //case NR_TURN_CLIENT_STATE_ALLOCATING:
@@ -147,21 +150,21 @@
              * because as a side effect this ctx may be operated on in the
              * callback */
             finished_cb(0,0,ctx->cb_arg);
         }
     }
 
     return(_status);
 }
 
 void
-nr_turn_client_cb(int s, int how, void *cb_arg)
+nr_turn_client_cb(NR_SOCKET s, int how, void *cb_arg)
 {
     int r,_status;
     nr_turn_client_ctx *ctx = (nr_turn_client_ctx*)cb_arg;
     nr_stun_client_ctx *stun_ctx = ctx->stun_ctx[ctx->phase];
 
     assert(ctx->phase >= 0);
 
     if ((r=nr_turn_client_next_action(ctx, stun_ctx->state)))
         ABORT(r);
 
@@ -234,21 +237,21 @@
 
     RFREE(ctx->username);
     r_data_destroy(&ctx->password);
 
     RFREE(ctx->label);
     RFREE(ctx);
 
     return(0);
 }
 
-int
+static int
 nr_turn_client_prepare_start(nr_turn_client_ctx *ctx, char *username, Data *password, UINT4 bandwidth_kbps, UINT4 lifetime_secs, NR_async_cb finished_cb, void *cb_arg)
 {
     int r,_status;
     nr_stun_client_allocate_request1_params          *allocate_request1 = 0;
     nr_stun_client_allocate_request2_params          *allocate_request2 = 0;
     nr_stun_client_allocate_response1_results        *allocate_response1 = 0;
 //    nr_stun_client_allocate_response2_results        *allocate_response2;
 
     if (ctx->state != NR_TURN_CLIENT_STATE_INITTED)
         ABORT(R_NOT_PERMITTED);
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/util/ice_util.c src/util/ice_util.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/util/ice_util.c	2012-09-16 16:26:10.000000000 -0700
+++ src/util/ice_util.c	2012-10-06 08:30:22.000000000 -0700
@@ -31,20 +31,21 @@
 */
 
 #include <stdarg.h>
 
 
 static char *RCSSTRING __UNUSED__="$Id: ice_util.c,v 1.2 2008/04/28 17:59:05 ekr Exp $";
 
 #include <stdarg.h>
 #include <string.h>
 #include "nr_api.h"
+#include "ice_util.h"
 
 int nr_concat_strings(char **outp,...)
   {
     va_list ap;
     char *s,*out=0;
     int len=0;
     int _status;
 
     va_start(ap,outp);
     while(s=va_arg(ap,char *)){
diff -U10 -r /Users/ekr/dev/mtransport-import-references/nICEr/src/util/mbslen.c src/util/mbslen.c
--- /Users/ekr/dev/mtransport-import-references/nICEr/src/util/mbslen.c	2012-09-16 16:26:10.000000000 -0700
+++ src/util/mbslen.c	2012-10-06 08:31:01.000000000 -0700
@@ -56,21 +56,21 @@
 {
 #ifdef DARWIN
     static locale_t loc = 0;
     static int initialized = 0;
 #endif /* DARWIN */
 #ifdef WIN32
     char *my_locale=0;
     unsigned int i;
 #endif  /* WIN32 */
     int _status;
-    int nbytes;
+    size_t nbytes;
     int nchars;
     mbstate_t mbs;
 
 #ifdef DARWIN
     if (! initialized) {
         initialized = 1;
         loc = newlocale(LC_CTYPE_MASK, "UTF-8", LC_GLOBAL_LOCALE);
     }
 
     if (loc == 0) {
@@ -102,25 +102,28 @@
 
     memset(&mbs, 0, sizeof(mbs));
     nchars = 0;
 
 #ifdef DARWIN
     while (*s != '\0' && (nbytes = mbrlen_l(s, strlen(s), &mbs, loc)) != 0)
 #else
     while (*s != '\0' && (nbytes = mbrlen(s, strlen(s), &mbs)) != 0)
 #endif /* DARWIN */
     {
-        assert(nbytes >= 0);
-        if (nbytes == (size_t)-1)   /* should never happen */
+        if (nbytes == (size_t)-1)   /* should never happen */ {
+	    assert(0);
             ABORT(R_INTERNAL);
-        if (nbytes == (size_t)-2)   /* encoding error */
+	}
+        if (nbytes == (size_t)-2)   /* encoding error */ {
+	    assert(0);
             ABORT(R_BAD_DATA);
+	}
  
         s += nbytes;
         ++nchars;
     }
 
     *ncharsp = nchars;
 
     _status = 0;
   abort:
 #ifdef WIN32
